﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ERP.ERPModels.Production.MasterData;
using ERP.MasterData.Dtos;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Caching.Memory;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.ObjectMapping;

namespace ERP.MasterData
{
    public class MaterialClassService : ApplicationService, IMaterialClassService
    {
        private readonly IRepository<MaterialClass, int> _repository;
        private readonly IMemoryCache _cache;
        private const string CACHE_KEY = "MaterialClassTree";
        private const int CACHE_MINUTES = 30; // 缓存30分钟

        public MaterialClassService(
            IRepository<MaterialClass, int> repository,
            IMemoryCache cache)
        {
            _repository = repository;
            _cache = cache;
        }

        public async Task<List<MaterialClassDto>> GetMaterialClassTreeAsync()
        {
            try
            {
                // 尝试从缓存获取
                if (_cache.TryGetValue(CACHE_KEY, out List<MaterialClassDto> cachedResult))
                {
                    Logger.LogDebug("从缓存获取物料分类数据，数量: {Count}", cachedResult.Count);
                    return cachedResult;
                }

                // 缓存未命中，从数据库查询
                Logger.LogDebug("缓存未命中，从数据库查询物料分类数据");
                var queryable = await _repository.GetQueryableAsync();
                
                // 优化查询：只查询必要字段，按排序字段排序
                var list = await queryable
                    .OrderBy(x => x.OrderById)
                    .ThenBy(x => x.Id)
                    .AsNoTracking() // 不跟踪实体变化，提高性能
                    .ToListAsync();

                var result = ObjectMapper.Map<List<MaterialClass>, List<MaterialClassDto>>(list);
                
                // 设置缓存
                var cacheOptions = new MemoryCacheEntryOptions
                {
                    AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(CACHE_MINUTES),
                    SlidingExpiration = TimeSpan.FromMinutes(10), // 10分钟内无访问则过期
                    Priority = CacheItemPriority.Normal
                };

                _cache.Set(CACHE_KEY, result, cacheOptions);
                Logger.LogDebug("物料分类数据已缓存，数量: {Count}", result.Count);

                return result;
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "获取物料分类树失败");
                throw;
            }
        }

        public async Task<MaterialClassDto> CreateAsync(CreateMaterialClassDto input)
        {
            try
            {
                var entity = ObjectMapper.Map<CreateMaterialClassDto, MaterialClass>(input);
                await _repository.InsertAsync(entity);
                await CurrentUnitOfWork.SaveChangesAsync();

                // 清除缓存
                _cache.Remove(CACHE_KEY);
                Logger.LogDebug("创建物料分类后清除缓存");

                return ObjectMapper.Map<MaterialClass, MaterialClassDto>(entity);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "创建物料分类失败");
                throw;
            }
        }

        public async Task<MaterialClassDto> UpdateAsync(int id, UpdateMaterialClassDto input)
        {
            try
            {
                var entity = await _repository.GetAsync(id);
                ObjectMapper.Map(input, entity);
                await _repository.UpdateAsync(entity);
                await CurrentUnitOfWork.SaveChangesAsync();

                // 清除缓存
                _cache.Remove(CACHE_KEY);
                Logger.LogDebug("更新物料分类后清除缓存");

                return ObjectMapper.Map<MaterialClass, MaterialClassDto>(entity);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "更新物料分类失败");
                throw;
            }
        }

        public async Task DeleteAsync(int id)
        {
            try
            {
                // 检查是否有子节点
                var queryable = await _repository.GetQueryableAsync();
                var hasChildren = await queryable.AnyAsync(x => x.ParentId == id);
                if (hasChildren)
                {
                    throw new UserFriendlyException("该分类下存在子分类，无法删除！");
                }

                await _repository.DeleteAsync(id);
                await CurrentUnitOfWork.SaveChangesAsync();

                // 清除缓存
                _cache.Remove(CACHE_KEY);
                Logger.LogDebug("删除物料分类后清除缓存");
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "删除物料分类失败");
                throw;
            }
        }

        public async Task<MaterialClassDto> GetAsync(int id)
        {
            try
            {
                var entity = await _repository.GetAsync(id);
                return ObjectMapper.Map<MaterialClass, MaterialClassDto>(entity);
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, "获取物料分类详情失败");
                throw;
            }
        }

        /// <summary>
        /// 清除缓存（用于手动刷新）
        /// </summary>
        public void ClearCache()
        {
            _cache.Remove(CACHE_KEY);
            Logger.LogInformation("手动清除物料分类缓存");
        }
    }
}
